package middleware

import (
	"fmt"
	"service/app/api"
	"service/app/control"
	"service/app/mode"
	"service/config"
	"service/global"
	"service/utils"
	"strings"

	"github.com/gin-gonic/gin"
	pathtoregexp "github.com/soongo/path-to-regexp"
	"github.com/spf13/viper"
	"gorm.io/gorm"
)

func AuthMiddlePerm() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		// 简便起见，假设用户从url传递 /xxxx?id=leo，实际应用可以结合jwt等鉴权
		token := ctx.GetHeader("Authorization")
		if token == "" {
			api.Fail(ctx, api.ResponseJson{Code: 403, Msg: "用户未在登录状态,请先登录!"})
			return
		}
		profile, err := utils.DecodeJwt(token)
		//TODO 从redis中取
		if err != nil {
			// 记录token过期或者非法用户
			clientIP := ctx.ClientIP()
			//TODO 报错样式修改
			global.Logger.Warn(fmt.Printf("错误事项:%s,ip:%s", err.Error(), clientIP))
			api.Fail(ctx, api.ResponseJson{Status: 401, Msg: "用户登录凭证失效,请重新登录!"})
			return
		}
		//FIXME 调试模式 admin,未设置有token但不用权限的
		if profile.NAME == "admin" {
			//test 管理员测试,auth (menu列表中)
			ctx.Set("user", &mode.Lz_user{Model: gorm.Model{ID: uint(profile.ID)}, User: profile.NAME})
		} else {
			var visitPath = ctx.Request.URL.Path
			var path = strings.Split(visitPath, viper.GetString("service.prefix"))
			var noNeedAuth = false
			for _, v := range config.NoNeedAuthPath {
				if v == path[len(path)-1] {
					noNeedAuth = true
				}
			}
			// 获取用户角色与perm
			var userControl = control.NewUserContr()
			userInfo, err := userControl.UserPermC(profile.ID)
			if err != nil {
				api.ServerFail(ctx, api.ResponseJson{Status: 500, Msg: "用户权限列表获取失败!"})
				return
			}
			// ctx中保存user资料
			ctx.Set("user", userInfo)
			if !noNeedAuth {
				var pass bool
				if len(userInfo.Roles) != 0 {
					for _, v := range userInfo.Roles {
						for i := 0; i < len(v.Perm); i++ {
							var item = v.Perm[i]
							// 使用依赖包 改PATH校验后 接受动态值 path[len(path)-1] "/role/perm/2" 所以无法匹配地址 "/role/perm/:id"
							matchUrl := pathtoregexp.MustMatch(item.Url, &pathtoregexp.Options{Decode: func(str string, token interface{}) (string, error) {
								return pathtoregexp.DecodeURIComponent(str)
							}})
							correct, err := matchUrl(path[len(path)-1]) //匹配的解析结果
							if err != nil {
								api.ServerFail(ctx, api.ResponseJson{Status: 500, Msg: "url解析错误失败!"})
								return
							}
							if correct != nil && ctx.Request.Method == item.Method {
								pass = true
								return
							}
						}
					}
				}
				if !pass {
					api.Fail(ctx, api.ResponseJson{Status: 403, Msg: "用户访问未授权页面,请联系管理员!", Code: 403})
					return
				}
			}
		}
		ctx.Next()
	}
}
